﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using EnCor.ObjectBuilder;
using EnCor.ModuleLoader;
using System.Xml;

namespace EnCor.Config
{
    public class ServiceConfig : NameTypeConfigElement
    {
        private bool _IsVerified = false;
        private readonly List<Type> _Interfaces = new List<Type>();

        public ServiceConfig()
        { 
            
        }

        public Type[] Interfaces
        {
            get
            {
                if (!_IsVerified)
                {
                    throw new ServiceConfigException(
                        "ServiceConfig has not been verified, please call Verify before use it.");
                }
                return _Interfaces.ToArray();
            }
        }

        private List<ServiceComponentConfig> _ComponentsConfig = new List<ServiceComponentConfig>();
        public IList<ServiceComponentConfig> ComponentsConfig
        {
            get
            {
                return _ComponentsConfig;
            }
        }

        [ConfigurationProperty(Constants.Config_DataType, DefaultValue = Constants.DefaultConfigType)]
        public string DataTypeName
        {
            get
            {
                return (string)this[Constants.Config_DataType];
            }
        }

        [ConfigurationProperty(Constants.Config_Interfaces)]
        public ServiceContractConfigCollection Contracts
        {
            get
            {
                return (ServiceContractConfigCollection)this[Constants.Config_Interfaces];
            }
        }

        [ConfigurationProperty(Constants.Config_Interface)]
        public string Interface
        {
            get { return (string) this[Constants.Config_Interface]; }
        }

        public Type DataType
        {
            get
            {
                return Type.GetType(DataTypeName);
            }
        }

        protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
        {
            if (name == Constants.Config_Interface)
            {
                Contracts.AddElement(new ServiceContractConfig(value));
                return true;
            }
            return base.OnDeserializeUnrecognizedAttribute(name, value);
        }

        protected override bool OnDeserializeUnrecognizedElement(string elementName, System.Xml.XmlReader reader)
        {
            if (Constants.Config_Component == elementName)
            {
                ServiceComponentConfig config = new ServiceComponentConfig();
                config.DeserializeElement(reader);
                if (config.Type == null)
                {
                    throw new ServiceConfigException(string.Format("Cannot find the type {0}", config.TypeName));
                }

                if (config.DataType == null)
                {
                    throw new ServiceConfigException(string.Format("Cannot find the type {0}", config.DataTypeName));
                }

                if (!(typeof(ServiceComponentConfig).IsAssignableFrom(config.DataType)))
                {
                    throw new ServiceConfigException("Invalid config type");
                }

                ServiceComponentConfig specialconfig = (ServiceComponentConfig)Activator.CreateInstance(config.DataType);
                specialconfig.DeserializeElement(reader);


                _ComponentsConfig.Add(specialconfig);
                return true;
            }

            return base.OnDeserializeUnrecognizedElement(elementName, reader);
        }

        /// <summary>
        /// 
        /// </summary>
        public void VerifyConfig()
        {
            if (!string.IsNullOrEmpty(Interface))
            {
                Type type = Type.GetType(Interface);
                _Interfaces.Add(type);
            }

            foreach ( ServiceContractConfig contractConfig in Contracts)
            {
                _Interfaces.Add(contractConfig.Type);
            }

            if (_Interfaces.Count== 0)
            {
                _Interfaces.Add(this.Type);
            }

            _IsVerified = true;
        }
    }
}
